/****************************************************************************
 * regfile_tb.v
 ****************************************************************************/

`include "../general/dffs.v" 
`include "../risc_t16_i_core/regfile.v"

/**
 * Module: regfile_tb
 * 
 * 寄存器文件模板
 * 寄存器文件包含两个读端口，一个写端口；不含复位信号。
 * 寄存器的写需要一个时钟的上升沿锁存，读的时候idx选通后立即输出，不需要时钟同步
 * 寄存器文件由D触发器实现
 * 需要重点解释的是：寄存器ID的位宽为5，大于16个寄存器需要的位宽4，作用是寄存器可以按照16位
 *                存取，也可以按照32位存取，取决于idx的最高位位0(16位存取)还是1(32位存取)
 */
`timescale 1ns / 10ps

module regfile_tb;

    parameter REG_NUM        = 16;
    parameter REG_ID_WIDTH   = 5;
    parameter REG_WIDTH      = 16;
    parameter PERI           = 10;

    reg                        clk;

    reg  [REG_ID_WIDTH-1 : 0]  rd_src1_idx;
    reg  [REG_ID_WIDTH-1 : 0]  rd_src2_idx;
    wire [REG_WIDTH*2-1 : 0]   rd_src1_dat;
    wire [REG_WIDTH*2-1 : 0]   rd_src2_dat;

    reg                        wr_dst_en;
    reg  [REG_ID_WIDTH-1 : 0]  wr_dst_idx;
    reg  [REG_WIDTH*2-1 : 0]   wr_dst_dat;

    regfile
    # (
        .REG_NUM(REG_NUM),
        .REG_ID_WIDTH(REG_ID_WIDTH),
        .REG_WIDTH(REG_WIDTH)
    )
    regfile_inst
    (
        .clk(clk),
        
        .rd_src1_idx(rd_src1_idx),
        .rd_src2_idx(rd_src2_idx),
        .rd_src1_dat(rd_src1_dat),
        .rd_src2_dat(rd_src2_dat),
        
        .wr_dst_en(wr_dst_en),
        .wr_dst_idx(wr_dst_idx),
        .wr_dst_dat(wr_dst_dat)
    );

    always #(PERI/2) clk = ~clk;

    initial
    begin
        $dumpfile("regfile_tb.vcd");
        $dumpvars(0, regfile_tb);

        clk = 1'b0;
        wr_dst_en = 1'b0;

        // 16位寄存器写测试
        #PERI wr_dst_en = 1'b1;
        wr_dst_idx = 0;
        wr_dst_dat = 15;
        repeat(15)
        begin
            #PERI
            wr_dst_idx = wr_dst_idx + 1;
            wr_dst_dat = wr_dst_dat + 1;
        end
        
        // 16位寄存器读测试
        #PERI
        rd_src1_idx = 0;
        rd_src2_idx = 0;
        repeat(15)
        begin
            #PERI
            rd_src1_idx = rd_src1_idx + 1;
            rd_src2_idx = rd_src2_idx + 1;
        end

        // 32位寄存器写测试
        #PERI wr_dst_en = 1'b1;
        wr_dst_idx = 24;
        wr_dst_dat = 32'hA0B0C0D0;
        repeat(7)
        begin
            #PERI
            wr_dst_idx = wr_dst_idx + 1;
            wr_dst_dat = wr_dst_dat + 1;
        end

        // 32位寄存器读测试
        #PERI
        rd_src1_idx = 24;
        rd_src2_idx = 24;
        repeat(7)
        begin
            #PERI
            rd_src1_idx = rd_src1_idx + 1;
            rd_src2_idx = rd_src2_idx + 1;
        end

        // RN寄存器写测试
        #PERI wr_dst_en = 1'b1;
        wr_dst_idx = 16;
        wr_dst_dat = 32'hf0f0f0f0;
        repeat(7)
        begin
            #PERI
            wr_dst_idx = wr_dst_idx + 1;
            wr_dst_dat = wr_dst_dat + 1;
        end

        // RN寄存器读测试
        #PERI
        rd_src1_idx = 16;
        rd_src2_idx = 16;
        repeat(7)
        begin
            #PERI
            rd_src1_idx = rd_src1_idx + 1;
            rd_src2_idx = rd_src2_idx + 1;
        end

        #PERI $finish;
    end

endmodule